wayland: unmap popup along with its toplevel
authorOlivier Fourdan <ofourdan@redhat.com>
Mon, 5 Sep 2016 15:53:38 +0000 (17:53 +0200)
committerOlivier Fourdan <ofourdan@redhat.com>
Mon, 12 Sep 2016 08:03:58 +0000 (10:03 +0200)
If an application umaps the toplevel from its popup callback, this can
lead to a protocol error.

Make sure we mark popup parent and use that to check if their parent is
the toplevel being unmapped in which case we shall unmap the popup first
to avoid the protocol error.

Bugzilla: https://bugzilla.gnome.org/show_bug.cgi?id=770906

gdk/wayland/gdkwindow-wayland.c

index ccd3bc4f32ad9d2c69c82441f82aa924778f8406..be9bf9890e469478a98c7f906e3b2456e9460106 100644 (file)
@@ -132,6 +132,7 @@ struct _GdkWindowImplWayland
   unsigned int awaiting_frame : 1;
   GdkWindowTypeHint hint;
   GdkWindow *transient_for;
+  GdkWindow *popup_parent;
   PositionMethod position_method;
 
   cairo_surface_t *staging_cairo_surface;
@@ -2009,6 +2010,7 @@ gdk_wayland_window_create_xdg_popup (GdkWindow      *window,
 
   wl_surface_commit (impl->display_server.wl_surface);
 
+  impl->popup_parent = parent;
   display->current_popups = g_list_append (display->current_popups, window);
 }
 
@@ -2329,6 +2331,28 @@ unmap_subsurface (GdkWindow *window)
   impl->display_server.wl_subsurface = NULL;
 }
 
+static void
+unmap_popups_for_window (GdkWindow *window)
+{
+  GdkWaylandDisplay *display_wayland;
+  GList *l;
+
+  display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
+  for (l = display_wayland->current_popups; l; l = l->next)
+    {
+       GdkWindow *popup = l->data;
+       GdkWindowImplWayland *popup_impl = GDK_WINDOW_IMPL_WAYLAND (popup->impl);
+
+       if (popup_impl->popup_parent == window)
+         {
+           g_warning ("Tried to unmap the parent of a popup");
+           gdk_window_hide (popup);
+
+           return;
+         }
+    }
+}
+
 static void
 gdk_wayland_window_hide_surface (GdkWindow *window)
 {
@@ -2337,6 +2361,8 @@ gdk_wayland_window_hide_surface (GdkWindow *window)
 
   unset_transient_for_exported (window);
 
+  unmap_popups_for_window (window);
+
   if (impl->display_server.wl_surface)
     {
       if (impl->dummy_egl_surface)